<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>reactive</title>
  </head>
  <body>
    <div id="root">
      <p>{{ count }}</p>
      <p v-text="count" id="aaa" class="bbb"></p>
      <p>{{ person.name }}</p>
      <button v-on:click="handleClick">按钮</button>
    </div>
    <script src="./js/mvvm.js"></script>
    <script src="./js/compile.js"></script>
    <script src="./js/observer.js"></script>
    <script src="./js/watcher.js"></script>
    <script>
      debugger;

      /*
        响应式原理：
          1. 数据代理：将data中的属性代理到this上，可以通过this直接访问数据
            遍历data所有属性，对每一个属性进行数据代理
            通过Object.defineProperty方法，将data中属性定义在vm上，同时定义属性get/set
            get/set实际访问的都是原data数据

          2. 数据劫持：将原data数据中所有属性进行重新定义，定义成响应式的属性
            遍历data所有属性，对每一个属性进行重新定义，定义成响应式
            通过Object.defineProperty方法，将data中属性进行重新定义，同时定义属性get/set，以及给每个属性创建了dep对象
              get方法中dep.depend方法，用来建立响应式联系（dep保存watcher、watcher保存dep）
              set方法中dep.notify方法，用来通知dep保存的所有watcher，调用cb方法来更新用户界面，从而达到响应式

          3. 模板解析：解析页面中的模板语法（插值语法和指令语法）
            - 将元素的所有子节点添加到文档碎片中
            - 解析文档碎片中的模板语法
              遍历所有子元素，判断是元素节点还是文本节点
                元素节点需要解析指令语法
                文本解析需要解析插值语法
              解析完后，所有模板语法（处理事件指令以外）new Watcher，同时watcher保存了更新用户界面的方法
              new Watcher会读取表达式的值 --> this.count
                此时触发数据代理阶段给属性设置的get，get方法中读取的是原data数据属性
                此时触发数据劫持阶段给原数据属性设置的get，get方法中会调用dep.depend方法，就会建立dep和watcher联系
              
            - 将解析好的文档碎片添加元素中生效

            将来点击按钮，执行this.count++。
              此时触发数据代理阶段给属性设置的set，set方法中设置的是原data数据属性
              此时触发数据劫持阶段给原数据属性设置的set, set方法中会调用dep.notify方法，
                通过dep找到所有watcher，调用watcher.cb来更新用户界面，从而达到响应式
      */
      new MVVM({
        el: "#root",
        // el: document.getElementById("root"),
        data: {
          count: 0,
          person: {
            name: "jack",
          },
        },
        methods: {
          handleClick() {
            this.count++;
          },
        },
      });
    </script>
  </body>
</html>
